/* ============================================================

Copyright (c) 2007 Advanced Micro Devices, Inc.  All rights reserved.
 
Redistribution and use of this material is permitted under the following 
conditions:
 ewrfgadsf
Redistributions must retain the above copyright notice and all terms of this 
license.
 
In no event shall anyone redistributing or accessing or using this material 
commence or participate in any arbitration or legal action relating to this 
material against Advanced Micro Devices, Inc. or any copyright holders or 
contributors. The foregoing shall survive any expiration or termination of 
this license or any agreement or access or use related to this material. 

ANY BREACH OF ANY TERM OF THIS LICENSE SHALL RESULT IN THE IMMEDIATE REVOCATION 
OF ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL.

THIS MATERIAL IS PROVIDED BY ADVANCED MICRO DEVICES, INC. AND ANY COPYRIGHT 
HOLDERS AND CONTRIBUTORS "AS IS" IN ITS CURRENT CONDITION AND WITHOUT ANY 
REPRESENTATIONS, GUARANTEE, OR WARRANTY OF ANY KIND OR IN ANY WAY RELATED TO 
SUPPORT, INDEMNITY, ERROR FREE OR UNINTERRUPTED OPERATION, OR THAT IT IS FREE 
FROM DEFECTS OR VIRUSES.  ALL OBLIGATIONS ARE HEREBY DISCLAIMED - WHETHER 
EXPRESS, IMPLIED, OR STATUTORY - INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED 
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 
ACCURACY, COMPLETENESS, OPERABILITY, QUALITY OF SERVICE, OR NON-INFRINGEMENT. 
IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, REVENUE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED OR BASED ON ANY THEORY OF LIABILITY 
ARISING IN ANY WAY RELATED TO THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE. THE ENTIRE AND AGGREGATE LIABILITY OF ADVANCED MICRO DEVICES, 
INC. AND ANY COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT EXCEED TEN DOLLARS 
(US $10.00). ANYONE REDISTRIBUTING OR ACCESSING OR USING THIS MATERIAL ACCEPTS 
THIS ALLOCATION OF RISK AND AGREES TO RELEASE ADVANCED MICRO DEVICES, INC. AND 
ANY COPYRIGHT HOLDERS AND CONTRIBUTORS FROM ANY AND ALL LIABILITIES, 
OBLIGATIONS, CLAIMS, OR DEMANDS IN EXCESS OF TEN DOLLARS (US $10.00). THE 
FOREGOING ARE ESSENTIAL TERMS OF THIS LICENSE AND, IF ANY OF THESE TERMS ARE 
CONSTRUED AS UNENFORCEABLE, FAIL IN ESSENTIAL PURPOSE, OR BECOME VOID OR 
DETRIMENTAL TO ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR 
CONTRIBUTORS FOR ANY REASON, THEN ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE 
THIS MATERIAL SHALL TERMINATE IMMEDIATELY. MOREOVER, THE FOREGOING SHALL 
SURVIVE ANY EXPIRATION OR TERMINATION OF THIS LICENSE OR ANY AGREEMENT OR 
ACCESS OR USE RELATED TO THIS MATERIAL.

NOTICE IS HEREBY PROVIDED, AND BY REDISTRIBUTING OR ACCESSING OR USING THIS 
MATERIAL SUCH NOTICE IS ACKNOWLEDGED, THAT THIS MATERIAL MAY BE SUBJECT TO 
RESTRICTIONS UNDER THE LAWS AND REGULATIONS OF THE UNITED STATES OR OTHER 
COUNTRIES, WHICH INCLUDE BUT ARE NOT LIMITED TO, U.S. EXPORT CONTROL LAWS SUCH 
AS THE EXPORT ADMINISTRATION REGULATIONS AND NATIONAL SECURITY CONTROLS AS 
DEFINED THEREUNDER, AS WELL AS STATE DEPARTMENT CONTROLS UNDER THE U.S. 
MUNITIONS LIST. THIS MATERIAL MAY NOT BE USED, RELEASED, TRANSFERRED, IMPORTED,
EXPORTED AND/OR RE-EXPORTED IN ANY MANNER PROHIBITED UNDER ANY APPLICABLE LAWS, 
INCLUDING U.S. EXPORT CONTROL LAWS REGARDING SPECIFICALLY DESIGNATED PERSONS, 
COUNTRIES AND NATIONALS OF COUNTRIES SUBJECT TO NATIONAL SECURITY CONTROLS. 
MOREOVER, THE FOREGOING SHALL SURVIVE ANY EXPIRATION OR TERMINATION OF ANY 
LICENSE OR AGREEMENT OR ACCESS OR USE RELATED TO THIS MATERIAL.

NOTICE REGARDING THE U.S. GOVERNMENT AND DOD AGENCIES: This material is 
provided with "RESTRICTED RIGHTS" and/or "LIMITED RIGHTS" as applicable to 
computer software and technical data, respectively. Use, duplication, 
distribution or disclosure by the U.S. Government and/or DOD agencies is 
subject to the full extent of restrictions in all applicable regulations, 
including those found at FAR52.227 and DFARS252.227 et seq. and any successor 
regulations thereof. Use of this material by the U.S. Government and/or DOD 
agencies is acknowledgment of the proprietary rights of any copyright holders 
and contributors, including those of Advanced Micro Devices, Inc., as well as 
the provisions of FAR52.227-14 through 23 regarding privately developed and/or 
commercial computer software.

This license forms the entire agreement regarding the subject matter hereof and 
supersedes all proposals and prior discussions and writings between the parties 
with respect thereto. This license does not affect any ownership, rights, title,
or interest in, or relating to, this material. No terms of this license can be 
modified or waived, and no breach of this license can be excused, unless done 
so in a writing signed by all affected parties. Each term of this license is 
separately enforceable. If any term of this license is determined to be or 
becomes unenforceable or illegal, such term shall be reformed to the minimum 
extent necessary in order for this license to remain in effect in accordance 
with its terms as modified by such reformation. This license shall be governed 
by and construed in accordance with the laws of the State of Texas without 
regard to rules on conflicts of law of any state or jurisdiction or the United 
Nations Convention on the International Sale of Goods. All disputes arising out 
of this license shall be subject to the jurisdiction of the federal and state 
courts in Austin, Texas, and all defenses are hereby waived concerning personal 
jurisdiction and venue of these courts.

============================================================ */


#ifndef _SAMPLES_H_
#define _SAMPLES_H_
/**
    \file Samples.h
    \brief File containing common declarations and comments for the samples

    \note The usual order of function call is
    \li Initialize()
    \li SetupKernel()
    \li SetupData() <-- Application specific
    \li CopyDataToGPU()
    \li CopyConstantsToGPU()
    \li RunProgram()
    \li ReadDataFromGPU()
    \li AnalyzeResults() <-- Application specific
    \li Cleanup()
    */
#include "cal.h"
#include "calcl.h"
#include "Timer.h"
/** 
 * \typedef Data
 * \brief Another name for DataRec
 */

/**
 * \struct DataRec
 * \brief Structure that is used to store data and passed 
 * between common sample functions.
 */
typedef struct DataRec
{
    /**
     * \brief union of pointers to memory that 
     * represents the data of the matrix
     */
    union
    {
        CALfloat*  f_data;
        CALuint*   u_data;
        CALint*    i_data;
        CALdouble* d_data;
        CALchar*   c_data;
    };
    /**
     * \var Width
     * \brief Width of the data matrix
     */
    CALuint Width;
    /**
     * \var Height
     * \brief Height of the data matrix
     */
    CALuint Height;
    /**
     * \var ComponentSize
     * \brief number of data points 
     * in a single vector, can be
     * either 1, 2, or 4
     */
    CALuint ComponentSize;
    /**
     * \var DataSize
     * \brief The width of the data
     * in bytes. i.e. sizeof(CALfloat)
     */
    CALuint DataSize;
    /**
     * \var Linear
     * \brief Flag to specifiy whether
     * to use linear memory or tiled memory
     */
    CALboolean Linear;
    /**
     * \var Scratch
     * \brief Flag to specify whether to
     * use the data in a scratch buffer
     * or not
     */
    CALboolean Scratch;
} Data;

/**
 * \typedef SampleInfo
 * \brief Another name for SampleInfoRec
 */

/**
 * \struct SampleInfoRec
 * \brief Structure that holds the common command line parameters
 * for all the samples
 */
typedef struct SampleInfoRec
{
    /**
     * \var Verbose
     * \brief Flag to trigger verbose output
     */
    CALboolean Verbose;
    /**
     * \var Verify
     * \brief Flag to trigger verification of results
     */
    CALboolean Verify;
    /**
     * \var PrintIL
     * \brief Flag to have the program display the kernel
     */
    CALboolean PrintIL;
    /**
     * \var Disassemble
     * \brief Flag to have the program display the disassembled kernel
     */
    CALboolean Disassemble;
    /**
     * \var Quiet
     * \brief Flag to surpress output
     */
    CALboolean Quiet;
    /**
     * \var Timing
     * \brief Flag to print out timing results
     */
    CALboolean Timing;
    /**
     * \var DeviceNum
     * \brief Parameter that specifies which device to connect to
     */
    CALuint    DeviceNum;
    /**
     * \var Width
     * \brief The number of data points wide the execution domain is
     */
    CALuint    Width;
    /**
     * \var Height
     * \brief The number of data points high the execution domain is
     */
    CALuint    Height;
    /**
     * \var Iterations
     * \brief The number of runs of the kernel program to take the average timing of
     */
    CALuint    Iterations;
    /**
     * \var SrcComponents
     * \brief The number of components in the input data
     */
    CALuint    SrcComponents;
    /**
     * \var SrcMemory
     * \brief The location to store the input data
     */
    CALchar    SrcMemory;
    /**
     * \var SrcCacheable
     * \brief Flag to determine whether to request cacheable input memory
     */
    CALboolean SrcCacheable;
    /**
     * \var DstComponents
     * \brief The number of components in the output data
     */
    CALuint    DstComponents;
    /**
     * \var DstMemory
     * \brief The location to store the output data
     */
    CALchar	   DstMemory;
    /**
     * \var DstCacheable
     * \brief Flag to determine whether to request cacheable output memory
     */
    CALboolean DstCacheable;
    /**
     * \var System
     * \brief Timer that handles the system timing information
     *
     * This timer should be used around the iteration loop of the sample to keep
     * track of the system time. System time includes copy data to gpu and readback.
     */
    CPerfCounter System;
    /**
     * \var Kernel
     * \brief Timer that handles the kernel timing information
     *
     * This timer is used by the RunProgram and RunComputeProgram functions to determine the
     * time spent in the kernel.
     */
    CPerfCounter Kernel;

} SampleInfo;


/**
 * \typedef SampleFeatures
 * \brief Another name for SamplesFeaturesRec
 */
/**
 * \struct SampleFeaturesRec
 * \brief Structure that contains flags for different ASIC features a sample may use.
 * This is used to determine whether the sample can be run on a particular ASIC. 
 */
typedef struct SampleFeaturesRec
{
    /**
     * \fn SampleFeaturesRec
     * \brief Constructor to initialize all members to false
     */
	SampleFeaturesRec()
	{
		DoublePrecision = CAL_FALSE; 
		ComputeShaders = CAL_FALSE;
		LocalDataShares = CAL_FALSE;
		MemExport = CAL_FALSE;
		GlobalDataShares = CAL_FALSE;
	}

    /**
     * \var DoublePrecision
     * \brief Flag to specify whether sample uses double precision
     */
    CALboolean DoublePrecision;
    /**
     * \var ComputeShaders
     * \brief Flag to specify whether sample uses compute shaders
     */
    CALboolean ComputeShaders;
    /**
     * \var LocalDataShares
     * \brief Flag to specify whether sample uses LDS
     */
    CALboolean LocalDataShares;
    /**
     * \var MemExport
     * \brief Flag to specify whether sample uses Mem Export
     */
    CALboolean MemExport;
    /**
     * \var GlobalDataShares
     * \brief Flag to specify whether sample uses Global Data Shares
     */
    CALboolean GlobalDataShares;
} SampleFeatures;

/**
 * \typedef DeviceInfo
 * \brief Another name for struct DeviceInfoRec.
 */
typedef struct DeviceInfoRec DeviceInfo;


/**
 * \typedef float4
 * \brief Another name for float4Rec
 */
/**
 * \struct float4Rec
 * \brief CPU struct that mimics the GPU float4 vector
 */
typedef struct float4Rec {
    /**
     * \var CALfloat x
     * \brief mimics the X components of the float4 vector
     */
    CALfloat x; 
    /**
     * \var CALfloat y
     * \brief mimics the Y components of the float4 vector
     */
    CALfloat y; 
    /**
     * \var CALfloat z
     * \brief mimics the Z components of the float4 vector
     */
    CALfloat z; 
    /**
     * \var CALfloat w
     * \brief mimics the W components of the float4 vector
     */
    CALfloat w; 
} float4;
/**
 * \typedef float2
 * \brief Another name for float2Rec
 */
/**
 * \struct float2Rec
 * \brief CPU struct that mimics the GPU float4 vector
 */
typedef struct float2Rec {
    /**
     * \var CALfloat x
     * \brief mimics the X components of the float2 vector
     */
    CALfloat x; 
    /**
     * \var CALfloat y
     * \brief mimics the Y components of the float2 vector
     */
    CALfloat y; 
} float2;

/**
 * \typedef CALVersion
 * \brief Another name for CALVersionRec
 */
/**
 * \struct CALVersionRec
 * \brief CPU struct that contains a CAL version
 */
typedef struct CALVersionRec {
/**
 * \var major
 * \brief CAL major version 
 */
CALuint major;

/**
 * \var minor
 * \brief CAL minor version
 */
CALuint minor;

/**
 * \var imp
 * \brief CAL imp 
 */
CALuint imp;
}CALVersion;

/**
 * \fn CALint Initialize(CALdevice* device, CALcontext* ctx, CALuint deviceNum)
 * \param device Pointer to CALdevice object to place device handle
 * \param ctx    Pointer to CALcontext object to place context handle
 * \param deviceNum device number to open
 * \return 0 on failure, non-zero on success
 * \brief Initializes the cal runtime and corresponding state
 *
 * The initialize function, as the name suggests, initializes the state
 * of cal and checks for errors. It uses the global variable DeviceNum
 * to open a device on the machine and stores the handle in \e CALdevice
 * pointed to by \a device. If the device is successfully created, then
 * the next step is to create a thread-safe context on that specific
 * device. When the context is created, the handle is stored in the
 * \e CALcontext that is pointed to by the \a ctx variable that is passed
 * in as the second argument. When all is said and done, the value
 * for success is returned.
 *
 * \warning Initialize must be called before any other cal related functions
 *
 * \code
 * // Initialize CAL, a CALdevice and a CALcontext
 * CALdevice device = 0;
 * CALcontext = ctx = 0;
 * if (!Initiaize(&device, &ctx))
 * {
 *     fprintf(stderr,"There was an error in initializing call. Exiting!\n");
 *     return 0;
 * }
 * \endcode
 */
CALint Initialize (CALdevice *device, CALcontext *ctx, CALuint deviceNum);

/**
 * \fn CALint SetupKernel(const CALchar* ILKernel, CALmodule* module, CALcontext* ctx, CALboolean disassemble)
 * \param ILKernel String containing the IL kernel to be compiled
 * \param module Pointer to CALmodule object to place module handle
 * \param ctx CAL Context to compile the kernel in
 * \param disassemble Flag to determine whether to disassemble kernel
 * \return 0 on failure, non-zero on success
 * \brief Compiles, links and loads a kernel into a \e CALmodule object
 *
 * SetupKernel compiles the passed in string, \a ILKernel, for the CAL
 * platform and target gpu. In order to get the target GPU, the device
 * is queried and based on the resulting values, the kernel is compiled
 * for the target GPU. On success of the compilation, the results are 
 * stored in a \e CALobject. The object is then linked to a \e CALimage
 * before being loaded into \e CALmodule that is pointed to by \a module.
 * At all points error checking is done and handled. If no error is 
 * detected, then success is returned.
 *
 * \note This function is called after Initialize and before SetupData
 *
 * \code
 * // Compile, Link and load the kernel into a cal module
 * CALmodule module;
 * if (!SetupKernel(ILKernel, &module, &ctx))
 * {
 *     fprintf(stderr, "Error setting up the kernel.  Exiting!\n");
 *     return 0;
 * }
 * \endcode
 */
CALint SetupKernel(const CALchar* ILKernel, CALmodule* module, CALcontext* ctx, CALboolean disassemble = CAL_FALSE);
/**
 * \fn CALint AssembleKernel(const CALchar* ILKernel, CALmodule* module, CALcontext* ctx, CALCLprogramType asmLang = CAL_PROGRAM_TYPE_PS, CALboolean Disassemble)
 * \param ILKernel String containing the IL kernel to be compiled
 * \param module Pointer to CALmodule object to place module handle
 * \param ctx CAL Context to compile the kernel in
 * \param asmLang CAL asm language type
 * \param Disassemble Flag on whether to spit out dissasembled image, defaults to false
 * \return 0 on failure, non-zero on success
 * \brief Compiles, links and loads a kernel into a \e CALmodule object
 *
 * AssembleKernel assembles the passed in string, \a ILKernel, for the CAL
 * platform and target gpu. In order to get the target GPU, the device
 * is queried and based on the resulting values, the kernel is compiled
 * for the target GPU. On success of the compilation, the results are 
 * stored in a \e CALobject. The object is then linked to a \e CALimage
 * before being loaded into \e CALmodule that is pointed to by \a module.
 * At all points error checking is done and handled. If no error is 
 * detected, then success is returned.
 *
 * \note This function is called after Initialize and before SetupData
 *
 * \code
 * // Assemble, Link and load the kernel into a cal module
 * CALmodule module;
 * if (!AssembleKernel(ILKernel, &module, &ctx))
 * {
 *     fprintf(stderr, "Error setting up the kernel.  Exiting!\n");
 *     return 0;
 * }
 * \endcode
 */
CALint AssembleKernel(const CALchar* ILKernel, CALmodule* module, CALcontext* ctx, CALCLprogramType asmLang = CAL_PROGRAM_TYPE_PS, CALboolean Disassemble = CAL_FALSE);

/**
 * \fn CALint RunProgram(CALcontext* ctx, CALmodule* module, CALuint Width, CALuint Height, SampleInfo* Info)
 * \param ctx Pointer to the \e CALcontext created in \e Initialize()
 * \param module Pointer to the \e CALmodule created in \e SetupKernel()
 * \param Width width of domain
 * \param Height height of domain
 * \param Info Info structure that holds the kernel counter
 * \return 0 on failure, non-zero on success
 * \brief Runs the kernel specified by the \a entryPoint, \a ctx and \a module
 *
 * RunProgram takes as input a context, module, entryPoint, and the
 * number of Iterations to run the program. Once the module's entry 
 * point is correctly setup and the domain is setup from the Width 
 * and Height variables. The function waits in a tight loop while 
 * the GPU runs the kernel. 
 *
 * \note This function should be called between SetupData and AnalyzeResults
 *
 * \code
 * CALdouble elapsedTime = 0.0;
 * CALint Iterations = 100;
 * if (!RunProgram(&ctx, &module, Info.Width, Info.Height, &Info))
 * {
 *      fprintf(stderr, "Error running the program. Exiting!\n");
 *      return 0;
 * }
 * \endcode
 */
CALint RunProgram(CALcontext* ctx, CALmodule* module, CALuint Width, CALuint Height, SampleInfo* Info);

/**
 * \fn CALint RunComputeProgram(CALcontext* ctx, CALmodule* module, CALuint Width, CALuint Height, SampleInfo* Info)
 * \param ctx Pointer to the \e CALcontext created in \e Initialize()
 * \param module Pointer to the \e CALmodule created in \e SetupKernel()
 * \param Width width of domain
 * \param Height height of domain
 * \param Info SampleInfo struct that holds the kernel timer
 * \return 0 on failure, non-zero on success
 * \brief Runs the kernel specified by the \a entryPoint, \a ctx and \a module
 *
 * RunComputeProgram takes as input a context, module, entryPoint, and the
 * number of Iterations to run the program. 
 * Once the module's entry point is correctly setup and the domain is 
 * setup from the Width and Height variables. The function waits in a tight 
 * loop while the GPU runs the kernel. 
 *
 * \note This function should be called between SetupData and AnalyzeResults
 *
 * \code
 * if (!RunComputeProgram(&ctx, &module, Info.Width, Info.Height, &Info))
 * {
 *      fprintf(stderr, "Error running the program. Exiting!\n");
 *      return 0;
 * }
 * \endcode
 */
CALint RunComputeProgram(CALcontext* ctx, CALmodule* module, CALuint Width, CALuint Height, SampleInfo* Info);

/**
 * \fn CALint Cleanup(CALdevice* device, CALcontext* ctx, CALmodule* module, CALresource* &resourceHandler, CALmem* &memoryHandler, Data* &data, CALuint numHandles, CALboolean waitForUser)
 * \param device Pointer to the device handle assigned in \e Initialize()
 * \param ctx    Pointer to the context handle assigned in \e Initialize()
 * \param module Pointer to the module handle assigned in \e SetupKernel()
 * \param resourceHandler Pointer to the resources handles assigned in \e AllocateResources()
 * \param memoryHandler Pointer to the memory handles assigned in \e AllocateResources()
 * \param data   Pointer to the Data handle assigned in \e SetupData
 * \param numHandles total number of handles that are being used
 * \param waitForUser Choice of waiting for user on cleanup
 * \return 0 on failure, non-zero on success
 * \brief Cleans-up the CAL environment by releasing handles and memory allocated by previous functions
 *
 *
 * \note Should not be called until after AnalyzeResults
 *
 * \code
 * // Free up memory allocated by previous functions
 * if (!Cleanup(&device, &ctx, &module, resourceHandler, memoryHandler, data, numInputs + numOutputs + numConstantBuffers), waitForUser)
 * {
 *      fprintf(stderr, "Error occurred while trying to shutdown CAL. Exiting!\n");
 *      return 0;
 * }
 * \endcode
 */
CALint Cleanup(CALdevice* device, CALcontext* ctx, CALmodule* module, CALresource* &resourceHandler, CALmem* &memoryHandler, Data* &data, CALuint numHandles, CALboolean waitForUser = CAL_FALSE);

/**
 * \fn CALformat getFormat(CALuint formatSize, CALuint dataSize)
 * \param formatSize The size of the format to get
 * \param dataSize size in bytes of the data, i.e. sizeof(CALfloat)
 * \return The format corresponding to \a comp
 *
 * \code
 * for (CALuint x = 0; x < 5; ++x)
 * {
 *     r = calResAllocLocal2D(&_Res[x], *device, Width, Height, getFormat(mNumComponents, sizeof(CALfloat)), 0);
 *     if (r != CAL_RESULT_OK)
 *     {
 *          fprintf(stderr, "Error occurred while trying to alloc Res %d\n", x);
 *          return 0;
 *     }
 * }
 * \endcode
 */
CALformat getFormat(CALuint formatSize, CALuint dataSize);

/**
 * \fn CALboolean ParseCommandLine(CALuint argc, CALchar *argv[], SampleInfo* Info)
 * \param argc number of arguments in the argument vector
 * \param argv the vector of arguments
 * \param Info structure the holds the parsed data specified by the common usage variables
 * \brief parses the argument vector to fill the global variables
 * \return CAL_TRUE on success, CAL_FALSE on error
 *
 * Parses the command line and assigns the resulting values to
 * global parameters that are specific to each sample.
 */
CALboolean ParseCommandLine(CALuint argc, CALchar* argv[], SampleInfo* Info);

/**
 * \fn CALvoid Usage(const CALchar* name)
 * \param name Name of the program being run
 * \brief Prints out the usage information of the sample program
 * \return No return value
 *
 * Prints out the usage for the Sample. The usage is custom to each
 * sample, but is required for a sample.
 *
 */
CALvoid Usage(const CALchar* name);
/**
 * \fn CALuint AnalyzeResults(Data* data)
 * \param data pointer to data matrices to analyze
 * \return 0 on failure, non-zero on success
 * \brief Analyzes and prints out information about the results
 *
 * \warning Must be called after RunProgram and before Cleanup
 *
 * \code
 *  if (!AnalyzeResults(&data[numInputs + numConstantBuffers]))
 *  {
 *      return 0;
 *  }
 * \endcode
 */
CALuint AnalyzeResults(Data* data);
/**
 * \fn int main(CALuint argc, CALchar** argv)
 * \param argc the number of arguments in the argument vector
 * \param argv the vector of arguments
 * \brief runs the sample program
 * \return 0 on failure, non-zero on success
 *
 * The main function goes through the following phases:
 * Input Parsing :     Parses the input to the program
 * Initialization:     Initializes CAL and system resources
 * Setup kernel  :     Compile and Link an IL kernel into a CALmodule
 * Setup Data    :     Setup custom program data (inputs/outputs etc) 
 * Execution     :     Load the CALmodule and run the kernel
 * Analyze       :     Analyze custom program results
 * Cleanup       :     Cleanup and Close any resources in use
 */

/**
 * \fn CALint SetupData(CALmodule* module, CALresource* &_Res, CALmem* &_Mem, Data* &data, CALdevice* device, CALcontext* ctx, CALuint numInputs, CALuint numOutputs, CALuint numConstantBuffers)
 * \param module the module to assign the memory locations to
 * \param _Res A reference to the location where CALres handlers will be allocated to
 * \param _Mem A reference to the location where CALmem handlers will be allocated to
 * \param data A reference to the location where Data handlers will be allocated to
 * \param device Pointer to the device to be worked on
 * \param ctx Pointer to the context of the device
 * \param numInputs number of input handlers to create
 * \param numOutputs number of output handlers to create
 * \param numConstantBuffers number of constant handlers to create
 * \return 0 on failure, non-zero on success
 * \brief Sets up the data and writes the data to the GPU to be used by the kernel
 *
 * SetupData is specific to this sample but the comments cover the generic
 * flow so that copying the structure is easy. The first step is to setup
 * the specific variables and the matrices for the data. Once they are setup,
 * then the resource and memory handles need to be setup. Usually the inputs
 * come first, followed by constants, then the outputs.
 * This usually is done by zero'ing out the memory with memset or
 * by copying data that was passed into the function. 
 * Once the memory has been set and the needed constants are set, the 
 * function should then map the names of the inputs/outputs in the kernel
 * to the corresponding memory locations. The final step is to clean up
 * any dynamic memory and returning success. If any \e CAL call fails,
 * then the result should not be returned, but a fail value of 0.
 * Once all the data has been setup in the data structure, then the
 * resources and memory handles are allocated, created, linked and bound
 * to the respective cal names.
 *
 * \warning Must be called after SetupKernel
 * \note The sample must implement this function, not Samples.cpp
 *
 * \code
 * // Initialize CALresource and CALmem handles
 * CALint numInputs = 1;
 * CALint numOutputs = 1;
 * CALint numConstantBuffers = 2;
 * CALresource* resourceHandler = NULL;
 * CALmem* memoryHandler = NULL;
 * Data* data = NULL;
 * if (!SetupData(&module, resourceHandler, memoryHandler, data, &device, &ctx,
 *                numInputs, numOutputs, numConstantBuffers))
 * {
 *      fprintf(stderr, "Error setting up the data. Exiting!\n");
 *      return 0;
 * }
 * \endcode
 */
extern CALint SetupData(CALmodule* module, CALresource* &_Res, CALmem* &_Mem, Data* &data, CALdevice* device, CALcontext* ctx, CALuint numInputs, CALuint numOutputs, CALuint numConstantBuffers);

/**
 * \fn CALvoid PrintKernel(const CALchar* string, const CALchar* name)
 * \param string the kernel to print in a formatted fashion.
 * \param name the name of the function to be printed
 * \brief a unified function to print out the kernel information
 *
 * This function provides a common method of printing the kernel  
 * in a formatted manner so that a single place is used to propagate
 * throughout all the samples.
 */
CALvoid PrintKernel(const CALchar* string, const CALchar* name);

/**
 * \fn CALvoid PrintPerfHeader(const CALchar* progName)
 * \param progName Name of the program to print the header for
 * \brief prints the header for displaying information about the performance
 * tests
 */
CALvoid PrintPerfHeader(const CALchar* progName);

/**
 * \fn CALvoid PrintPerfStats(CALuint nInput, CALuint nOutput, SampleInfo& Info, CALuint Bytes)
 * \param nInput The number of input memory accesses
 * \param nOutput The number of output memory access
 * \param Info Structure that holds all the relevant size information
 * \param Bytes Width of the data type in bytes(i.e. sizeof(CALfloat))
 */
CALvoid PrintPerfStats(CALuint nInput, CALuint nOutput, SampleInfo& Info, CALuint Bytes);

/**
 * \fn CALint CopyDataFromGPU(CALcontext* ctx, CALresource* _Res, Data* data, CALuint num)
 * \param ctx Context of the current GPU
 * \param _Res Pointer to the first resource
 * \param data Pointer to the first data matrix to be copied back
 * \param num Number of data matrices to be copied back
 * \return Returns 0 on failure and 1 on success
 *
 * \brief Copies data from CPU to GPU
 *
 * This function loops through num times and copies the information from the resource on the GPU 
 * to the corresponding data structure using the correct pitch and alignment. It also takes into
 * account whether the data should be copied linearly or not.
 *
 * \warning the number of _Res and data points allocated must be equal to or greater than num
 */
CALint CopyDataFromGPU(CALcontext* ctx, CALresource* _Res, Data* data, CALuint num);

/**
 * \fn CALint CopyDataToGPU(CALcontext* ctx, CALresource* _Res, Data* data, CALuint num)
 * \param ctx Context of the current GPU
 * \param _Res Pointer to the first resource
 * \param data Pointer to the first data matrix to be copied over
 * \param num Number of data matrices to be copied over
 * \return 0 on failure and 1 on success
 *
 * \brief Copies data from CPU to GPU
 *
 * This function loops through num times and copies the information from the Data structure
 * to the corresponding resource using the correct pitch and alignment. It also takes into
 * account whether the data should be copied linearly or not.
 *
 * \warning the number of _Res and data points allocated must be equal to or greater than num
 */
CALint CopyDataToGPU(CALcontext* ctx, CALresource* _Res, Data* data, CALuint num);

/**
 * \fn CALint BindIONames(CALcontext* ctx, CALmodule* module, CALmem* _Mem, CALuint iStop, CALuint cStop, CALuint oStop, Data* data)
 * \param ctx Context of the current GPU
 * \param module Module to get the name information from
 * \param _Mem CAL memory resource to bind the name to
 * \param iStop Place to stop assigning input names to
 * \param cStop Place to stop assigning constant names to
 * \param oStop Place to stop assigning output names to
 * \param data Array of data matrices that coincide with the memory being bound
 * \brief Binds all the input, output and constant names to the memory locations for the kernel 
 * \return 0 on failure 1 on success
 */
CALint BindIONames(CALcontext* ctx, CALmodule* module, CALmem* _Mem, CALuint iStop, CALuint cStop, CALuint oStop, Data* data);

/**
 * \fn CALint AllocateResources(CALcontext* ctx, CALdevice* device, CALresource* &_Res, CALmem* &_Mem, CALuint iStop, CALuint cStop, CALuint oStop, Data* data, const SampleInfo& Info)
 * \param ctx Context of the current GPU
 * \param device GPU device to allocate memory on
 * \param _Res Pointer to resource handles
 * \param _Mem Pointer to memory handles
 * \param iStop Index to stop allocating resources for inputs
 * \param cStop Index to stop allocating resources for constants
 * \param oStop Index to stop allocating resources for outputs
 * \param data Array of data matrices that coincide with the resources being created
 * \param Info SampleInfo data structure that holds command line information 
 * \brief Creates resources of sizes that match the matrices in the data array.
 * \return 0 on failure 1 on success
 */
CALint AllocateResources(CALcontext* ctx, CALdevice* device, CALresource* &_Res, CALmem* &_Mem, CALuint iStop, CALuint cStop, CALuint oStop, Data* data, const SampleInfo& Info);


/**
 * \fn CALvoid AllocateMemory(Data& data, CALuint tWidth, CALuint tHeight, CALuint CompSize, CALuint DataSize, CALresallocflags flags)
 * \param data reference to the data matrix to allocate data for
 * \param tWidth Width of data matrix
 * \param tHeight Height of data matrix
 * \param CompSize Size of the components, either 1, 2, or 4
 * \param DataSize Size of each data element, i.e. sizeof(CALfloat)
 * \param flags Flag to specify either linear or tiled format
 * \brief Allocates and sets up a Data struct with the passed in data
 */
CALvoid AllocateMemory(Data& data, CALuint tWidth, CALuint tHeight, CALuint CompSize, CALuint DataSize, CALresallocflags flags);

/**
 * \fn CALint ParameterValidation(CALuint nInput, CALuint nOutput, SampleInfo* Info, CALdeviceattribs* attribs)
 * \param nInput number of input textures being used
 * \param nOutput number of output textures being used
 * \param Info Sample info struct to check if there is enough requested spec on the device with the specific context
 * \param attribs Attributes of the device to determine if enough space is available
 * \brief Determine based on the command line parameters if there is enough space on the device to run the program
 * \return 0 for insufficient space and 1 for sufficient space.
 */
CALint ParameterValidation(CALuint nInput, CALuint nOutput, SampleInfo* Info, CALdeviceattribs* attribs);

/**
 * \fn CALint SupportedCALVersion(CALVersion *calVersion)
 * \param calVersion Pointer to a CALVersion struct
 * \brief Fills the struct pointed to by calVersion with the 
 * version of the CAL runtime currently supported by the SDK
 */
CALvoid SupportedCALVersion(CALVersion *calVersion);

/**
 * \fn CALint QueryDeviceCaps(CALuint DeviceNum, SampleFeatures *FeatureList)
 * \param DeviceNum Device number for the device that is to be checked for capability
 * \param FeatureList struct containing flags for features used by the sample
 * \brief Determine based on input SampleFeatures structure whether 
 * this device is capable of running the sample
 * \return 0 for incapable and 1 for capable.
 */
CALint QueryDeviceCaps(CALuint DeviceNum, SampleFeatures *FeatureList);

/**
 * \fn CALint QueryCALVersion(CALVersion required, const CALchar* comparison)
 * \param required The required CAL version 
 * \param comparison The type of comparison. Must be one of ">" "<" "==" "<=" ">="
 * \brief Compare available CAL version with required one
 * Returns the result of: Available |comparison| Required
 * \return 0 for FALSE, 1 for TRUE.
 */
CALint QueryCALVersion(CALVersion required, const CALchar *comparison);

/**
 * \fn CALint ValidateCALRuntime()
 * \brief Validates whether the available CAL runtime is supported by the SDK
 * \return 0 for NO, 1 for YES.
 */
CALint ValidateCALRuntime();

#endif // _SAMPLES_H_
